package cn.edu.fudan.rule;

import cn.edu.fudan.data.*;
import cn.edu.fudan.tools.GetConfig;
import cn.edu.fudan.type.*;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by 80494 on 2017/4/10.
 */
public class WaveletRuleClassifier {

    private static Logger logger = Logger.getLogger(WaveletRuleClassifier.class);
    //private static PAMAPDimension dimension = PAMAPDimension.z_ankle;
    //public WaveletRuleClassifier(String subject) {
    //public static void main(String[] args) throws IOException {
    //    double support=0.4;
    //    double confidence=0.4;
    public void WaveletRuleClassifier (double support,double confidence){
        System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
        String subject = "subject101";
        PAMAPDimension dimension = PAMAPDimension.z_ankle;
        Config config;
        try {
            config = new GetConfig().getConfig();
            logger.info(config);

            String path = config.getPath();

            String filePath = path + subject + "_extract";
            String trainPath = path + subject + "\\train.txt";
            String testPath = path + subject + "\\test.txt";

            ReadData readData = new ReadData();
            ExtractFeature extractFeature = new ExtractFeature();
            HandelFeature handelFeature = new HandelFeature();
            SlideWindow slideWindow = new SlideWindow();
            HandleDistance handleDistance = new HandleDistance();
            WaveletPre waveletPre =new WaveletPre();
            RulePruning rulePruning=new RulePruning();
            RuleGeneration ruleGeneration= new RuleGeneration();
            Classifier classifier=new Classifier();

            List<List<DataItem>> database =new ArrayList<>();
            List<WaveletPerOrder> trainpre =new ArrayList<>();
            List<WaveletPerOrder> testpre =new ArrayList<>();
            List<Rule> ruleset =new ArrayList<>();

            int count =0;
            double accuracy =0.0;

            List<DataItem> data = new ArrayList<DataItem>();
            List<List<Long>> timepoints = new ArrayList<>();
            List<List<Long>> testpoints = new ArrayList<>();



            try {
                data = readData.readPAMAPDataFromFile(filePath, true, dimension);
                timepoints = readData.readTimePoint(trainPath, true);

                testpoints = readData.readTimePoint(testPath, true);
            } catch (Exception e) {
                // TODO Auto-generated catch block e.printStackTrace();
            }
            if (data.size() > 0) {
                long begin = System.currentTimeMillis();
                Feature feature = extractFeature.getFeature(data, config.getThreshold_window(), config.getProbability(),
                        config.getInterval());

                // two-class
                List<List<DataItem>> data_A = slideWindow.extractWindow(feature.getAbnormal(), timepoints.get(0),
                        config.getWindow_length());
                List<List<DataItem>> data_B = slideWindow.extractWindow(feature.getAbnormal(), timepoints.get(1),
                        config.getWindow_length());

                List<List<DataItem>> test_A = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(0),
                        config.getWindow_length());
                List<List<DataItem>> test_B = slideWindow.extractWindow(feature.getAbnormal(), testpoints.get(1),
                        config.getWindow_length());

                List<List<DataItem>> trainingrawdata = data_A;
                trainingrawdata.addAll(data_B);
                List<List<DataItem>> testrawdata =test_A;
                testrawdata.addAll(test_B);

                System.out.println("");
                long start = System.currentTimeMillis();


                WaveletPerOrder trainpre_a =new WaveletPerOrder();
                WaveletPerOrder trainpre_b =new WaveletPerOrder();
                WaveletPerOrder testpre_b =new WaveletPerOrder();
                WaveletPerOrder testpre_a =new WaveletPerOrder();

                for (int i=0;i<data_A.size();i++) {
                    trainpre_a=waveletPre.WaveletPre(data_A.get(i));
                    trainpre_a.setLabel(0);
                    trainpre.add(trainpre_a);
                }
                for (int i=0;i<data_B.size();i++) {
                    trainpre_b=waveletPre.WaveletPre(data_B.get(i));
                    trainpre_b.setLabel(1);
                    trainpre.add(trainpre_b);
                }

                //RuleGeneration(List<WaveletPerOrder> traindataset, double minsupport, double minconfidence, int maxgap, int kclass)

                long rulegenstart = System.currentTimeMillis();
                ruleset=ruleGeneration.RuleGeneration(trainpre,support,confidence,trainpre.size(),2);
                long rulegenend = System.currentTimeMillis();

                TwoTuple<List<Rule>,Integer> twotuple = rulePruning.RulePruning(ruleset,trainpre,2);


                for (int i=0;i<test_A.size();i++) {
                    testpre_a= waveletPre.WaveletPre(test_A.get(i));
                    testpre_a.setLabel(0);
                    testpre.add(testpre_a);
                }
                for (int i=0;i<test_B.size();i++) {
                    testpre_b= waveletPre.WaveletPre(test_B.get(i));
                    testpre_b.setLabel(1);
                    testpre.add(testpre_b);
                }



                for (int i=0;i<testrawdata.size();i++){
                    if (classifier.Classifier(testrawdata.get(i),twotuple.first,twotuple.second)== testpre.get(i).getLabel()){
                        count++;
                    }
                }
                accuracy=(double) count/(double)testrawdata.size();

                long end = System.currentTimeMillis();
                logger.info( "The support is set to "+support +", and confidence is set to "+ confidence);
                logger.info("Got " + ruleset.size() + "rules" );
                logger.info("Run for " + (rulegenstart - rulegenend) / (double) 1000 + "seconds  for generate rule.");
                logger.info("Run for " + (end - start) / (double) 1000 + "seconds.");
                logger.info("Accuracy is:" + accuracy );
            }


        } catch (IOException e1) { // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        }
    }